from rest_framework import serializers
from django.db import transaction
from .models.case import *

PROTOCOLS = ["http_api", "sql_api", "thrift_api"]


# 协议接口基础序列化器
class ProtocolSerializer(serializers.Serializer):
    protocol_type = serializers.ChoiceField(
        choices=["http", "thrift", "sql"], read_only=True
    )


# HTTP协议专用
class HttpApiSerializer(serializers.ModelSerializer):
    class Meta:
        model = HttpApiModel
        fields = "__all__"


# Thrift协议专用
class ThriftApiSerializer(serializers.ModelSerializer):
    class Meta:
        model = ThriftApiModel
        fields = "__all__"


# SQL协议专用
class SqlApiSerializer(serializers.ModelSerializer):
    class Meta:
        model = SqlApiModel
        fields = "__all__"


# 测试步骤序列化器
class CaseStepSerializer(serializers.ModelSerializer):
    http_api = HttpApiSerializer(required=False)
    thrift_api = ThriftApiSerializer(required=False)
    sql_api = SqlApiSerializer(required=False)

    class Meta:
        model = CaseStep
        fields = [
            "id",
            "name",
            "step",
            "variables",
            "setup_hooks",
            "teardown_hooks",
            "extract",
            "export",
            "validators",
            "validate_script",
            "retry_times",
            "retry_interval",
            "http_api",
            "thrift_api",
            "sql_api",
        ]

    def validate(self, data):
        """验证协议类型唯一性"""
        if any((data.get(protocol, None) for protocol in PROTOCOLS)):
            raise serializers.ValidationError("步骤不能为空")
        return data

    def create(self, validated_data):
        """创建嵌套协议对象"""
        protocol_type = next((p for p in PROTOCOLS if p in validated_data), None)
        if protocol_type:
            protocol_data = validated_data.pop(protocol_type)
            model_class = {
                "http_api": HttpApiModel,
                "thrift_request": ThriftApiModel,
                "sql_request": SqlApiModel,
            }[protocol_type]

            protocol = model_class.objects.create(**protocol_data)
            validated_data[protocol_type] = protocol

        return super().create(validated_data)


# 测试用例序列化器
class CaseSerializer(serializers.ModelSerializer):
    steps = CaseStepSerializer(many=True, source="cases_step")

    class Meta:
        model = CaseModel
        exclude = ["report"]
        read_only_fields = ["status", "create_time", "update_time"]

    def create(self, validated_data):
        steps_data = validated_data.pop("cases_step", [])
        case = CaseModel.objects.create(**validated_data)
        self._create_steps(case, steps_data)
        return case

    def _create_steps(self, case, steps_data):
        for step_data in steps_data:
            protocol_type = step_data.pop("protocol_type")
            step = CaseStep.objects.create(case=case, **step_data)
            # 根据协议类型创建对应接口
            if protocol_type == "http":
                HttpApiModel.objects.create(**step_data["http_api"], step=step)
            elif protocol_type == "thrift":
                ThriftApiModel.objects.create(**step_data["thrift_request"], step=step)
            elif protocol_type == "sql":
                SqlApiModel.objects.create(**step_data["sql_request"], step=step)


class CaseCreateSerializer(serializers.ModelSerializer):
    steps = CaseStepSerializer(many=True, required=False)

    class Meta:
        model = CaseModel
        fields = "__all__"
        extra_kwargs = {"report": {"required": False}}

    def create(self, validated_data):
        steps_data = validated_data.pop("steps", [])
        with transaction.atomic():
            case = CaseModel.objects.create(**validated_data)
            for step_data in steps_data:
                protocol_type = next(
                    (key for key in PROTOCOLS if key in step_data), None
                )
                step = CaseStep.objects.create(
                    case=case,
                    **{k: v for k, v in step_data.items() if k not in PROTOCOLS}
                )

                if protocol_type == "http_api":
                    HttpApiModel.objects.create(step=step, **step_data["http_api"])
                elif protocol_type == "thrift_request":
                    ThriftApiModel.objects.create(
                        step=step, **step_data["thrift_request"]
                    )
                elif protocol_type == "sql_request":
                    SqlApiModel.objects.create(step=step, **step_data["sql_request"])
        return case
